                            Machine Language
                                Part III
                                   by
                               Lyle Giese

                           DELPHI Mail: LYLEG


Last month, I showed you how to print to the screen. This month we will
print the alphabet to the screen. And next month we will look into disk
I/O. Now don't let this scare you away. It is really not that hard. It
does take a few steps more than you would need in BASIC, but the
increase in speed is well worth it.

To start off here is this month's program. Again I am using the simple
assembler put the program in memory.
 
.A C000 LDA #$01
.A C002 LDX #$04
.A C004 LDY #$07
.A C006 JSR $FFBA
.A C009 LDA #$00
.A C00B JSR $FFBD
.A C00E JSR $FFC0
.A C011 LDX #$01
.A C013 JSR $FFC9
.A C016 LDY #$41
.A C018 TYA
.A C019 JSR $FFD2
.A C01C INY
.A C01D CPY #$5B
.A C01F BNE $C018
.A C021 LDA #$0D
.A C023 JSR $FFD2
.A C026 JSR $FFCC
.A C029 LDA #$01
.A C02B JSR $FFC3
.A C02E RTS
.A C02F <CR>
 
Definately, a little more typing but it is not that hard to figure out.
The key to it is learning to read the Kernal information in the
Programers Reference Guide. As I have been doing in the previous
articles, will be using the 64's PRG.

So we want to send some characters (in this case the alphabet) to the
printer. How do we do it in BASIC? We must first issue an OPEN command.
And we will do the same in ML.

If you look at page 289 in the PRG, you will find that the Kernal has a
routine called OPEN. How do we use it? Lets take a look at the
information there.

First it tells us what the routine does, open a logical file. Then it
gives us the address we need to call the routine. How we communicate
with it is next; but it says none. How do we tell it the secondary
address, logical file number, or even the device number?

That is what the next entry cares for. What routines need to be called
before this one can be called, Preparatory routines. And that is what I
did in my little program above.

So it says we need to call SETLFS first. So let's go there and take a
look at it. It tells us to set up a logical file. Its address is $FFBA
and we use all three registers to communicate with it. No preparatory
routines are needed. It returns no error codes, needs room for 2 entrys
in the stack, and returns with the A, X, and Y registers intact.

In the description, we find out that the Accumlator is loaded with the
logical file number($01). The X register is loaded with the device
number($04) and the Y register is loaded with the secondary
address($07). Be sure to note the Y register is loaded with $FF(255) if
you don't want to send a secondary address. And then we call the routine
with the JSR $FFBA at $C006.

Now we need to call the secondary preparatory routine-SETNAM. SETNAM is
used to set up the file name for the logical file. When doing I/O to a
cassette or disk drive, this is important. But to a printer?? Well we
just set the length of the filename to zero. As you read the description
of this routine, you will find that we do that by putting a zero in the
accumlator. If we did have a filename, the address of it would go into
the X(low order byte) and the Y(high order byte) registers. And at $C00B
we JSR $FFBD and complete that preparatory routine.

Now we can open out file by a JSR $FFC0. Note that all registers are
affected. If you had some information you wanted to save you would have
to copy it into a memory location prior to calling this routine and
restore it afterwards.

In my example, I did not check the error status after the open. But in a
bigger program or if the logical file is a disk or cassette file, you
would at this point check for errors in opening the file. You do this by
the READST routine. If we didn't and we forgot to hook up the printer to
the computer, the alphabet would be sent to the screen.

Now again let's go back to BASIC for a moment. We have opened our
logical file to the printer. In BASIC how do we direct our output to the
printer? With the CMD#1 command. In ML you have to open an output
channel to the device. The routine for this is CHKOUT.

The description for CHKOUT says that we have to use the OPEN routine
first, which we have. The X register is the communication register. We
put the number of the logical file in it($01). Make sure you use the
logical file and not the device number. And of course note that the
Accumlator and X register are changed during the routine.

Now we have the logical file open and the output being directed to the
printer. How do we send it? Time for the good old CHROUT routine. And if
we read the description of it, it tells us that we must use the CHKOUT
and OPEN routines first if we are sending to something other than to the
screen, which we have already done.

We load the PETSCII code for the letter "A" into the Accumlator and then
call the CHROUT routine and then increase the accumlator and check if we
have printed all of the alphabet. And branch back to print if not,
right? NO! Absolutely not!

This was the first big mistake I made when I started to program in ML. I
did not read or comprehend the entry 'Registers affected: .A' in the
description of CHROUT. That means the Accumlator is CHANGED while
executing this routine. We have to have some other means of keeping
track of the desired value. I decided to use the Y register in this
program. So we start out by putting the value of $41(the letter a) in
the Y register and copying that into the Accumlator.

Now we call the CHROUT($FFD2) routine. Upon exiting we INY(remember it
is not affected by CHROUT) and check if it is Z+1 or $5B. If it is not
we branch back to the TYA instruction and reload the Accumlator and
print it again.

Now after 26 times through the loop, we have sent the entire alphabet to
the printer. We fall through the BNE instruction at $C021. We load the
value of $0D (a plain old carriage return) and send it out to the
printer. Why?

Most (but not all) printers buffer incoming characters until a carriage
return or 80 characters are received before printing. So it is a good
habit to get into, that of sending a carriage return just before closing
the printer's output file.

Now we must tidy things up a bit by restoring the screen as the output
device. That routine is called CLRCHN and we call it with a JSR $FFCC.
Now we must close the logical file #1. We do that by loading the
Accumlator with the logical file number($01) and then JSR $FFC3(CLOSE).

And we return to where we were when we called this short routine with
the RTS instruction.

One thing I can tell you for sure---this explanation takes a lot longer
to read than it takes to execute!

Lyle Giese (Delphi Mail:  LYLEG)
